package online.heycm.platform.redis;

import online.heycm.platform.redis.aop.IdempotentAop;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * 单点Redis配置
 *
 * @author heycm
 * @since 2023/11/11 16:19
 */
@Configuration
@EnableConfigurationProperties({RedisProperties.class, RedisNamespace.class})
public class RedisCacheAutoConfiguration {

    private final RedisProperties redisProperties;

    private final RedisNamespace redisNamespace;

    public RedisCacheAutoConfiguration(RedisProperties redisProperties, RedisNamespace redisNamespace) {
        this.redisProperties = redisProperties;
        this.redisNamespace = redisNamespace;
    }

    /**
     * 单点模式
     */
    @Bean(name = "redisConnectionFactory")
    @ConditionalOnProperty(value = "spring.redis.host")
    public RedisConnectionFactory standaloneRedisConnectionFactory() {
        JedisClientConfiguration jedisClientConfiguration = RedisCacheUtil.createJedisClientConfiguration(
                redisProperties);
        RedisStandaloneConfiguration redisStandaloneConfiguration = RedisCacheUtil.createRedisStandaloneConfiguration(
                redisProperties);
        return new JedisConnectionFactory(redisStandaloneConfiguration, jedisClientConfiguration);
    }

    /**
     * 哨兵模式
     */
    @Bean(name = "redisConnectionFactory")
    @ConditionalOnProperty(value = "spring.redis.sentinel.nodes")
    public RedisConnectionFactory sentinelRedisConnectionFactory() {
        JedisClientConfiguration jedisClientConfiguration = RedisCacheUtil.createJedisClientConfiguration(
                redisProperties);
        RedisSentinelConfiguration redisSentinelConfiguration = RedisCacheUtil.createRedisSentinelConfiguration(
                redisProperties);
        return new JedisConnectionFactory(redisSentinelConfiguration, jedisClientConfiguration);
    }

    /**
     * 集群模式
     */
    @Bean(name = "redisConnectionFactory")
    @ConditionalOnProperty(value = "spring.redis.cluster.nodes")
    public RedisConnectionFactory clusterRedisConnectionFactory() {
        JedisClientConfiguration jedisClientConfiguration = RedisCacheUtil.createJedisClientConfiguration(
                redisProperties);
        RedisClusterConfiguration redisClusterConfiguration = RedisCacheUtil.createRedisClusterConfiguration(
                redisProperties);
        return new JedisConnectionFactory(redisClusterConfiguration, jedisClientConfiguration);
    }

    @Bean
    @ConditionalOnBean(RedisConnectionFactory.class)
    public RedisTemplate<String, Object> redisTemplate(
            @Qualifier("redisConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
        return RedisCacheUtil.createRedisTemplate(redisConnectionFactory);
    }

    @Bean
    @ConditionalOnBean(RedisConnectionFactory.class)
    public RedisCache redisCacheNamespace(RedisTemplate<String, Object> redisTemplate) {
        return new RedisCacheImpl(redisTemplate, redisNamespace.getNamespace());
    }

    @Bean
    @ConditionalOnBean(RedisCache.class)
    public IdempotentAop idempotentAop(RedisCache redisCache) {
        return new IdempotentAop(redisCache);
    }
}
